package devops

import (
	"fmt"
	"os"
	"strconv"
	"strings"

	"away.wei/minidevpos/db"
	"away.wei/minidevpos/global"
	"away.wei/minidevpos/model"
)

type DevOpsWorkSpace struct {
	DevOpsTask
	project          db.Project // 项目信息
	workspace_folder string     // 工作路径
	workspace_log    string     // 日志路径
	logfile          string     // 日志文件
	envs             map[string]string
}

func (s *DevOpsWorkSpace) New(devopsTask DevOpsTask) (err error) {
	s.DevOpsTask = devopsTask
	s.envs = map[string]string{}
	s.project, err = projectRep.Details(devopsTask.projectId)
	if err != nil {
		return err
	}

	abpath := global.Abpath
	s.workspace_log = CreateDir(abpath, "log", strconv.Itoa(s.project.ID))
	s.workspace_folder = CreateDir(abpath, "workspace", strconv.Itoa(s.project.ID))
	s.logfile = fmt.Sprintf("%s/%s.log", s.workspace_log, strconv.Itoa(devopsTask.deployNum))

	s.envs["DeloyNum"] = strconv.Itoa(s.deployNum)
	s.envs["ProjectName"] = s.project.Name
	return nil
}

func (s *DevOpsWorkSpace) Build() (status int, err error) {
	if _, err = os.Stat(fmt.Sprintf("%s/.git", s.workspace_folder)); os.IsNotExist(err) {
		cmd := make([]string, 0)
		cmd = append(cmd, "git init")
		cmd = append(cmd, fmt.Sprintf("git remote add origin %s", s.project.Git))
		cmd = append(cmd, "git fetch --all --prune")
		cmd = append(cmd, "git checkout master")
		shell := s.NewShell()
		shell.SetDir(s.workspace_folder)
		err := shell.Script(strings.Join(cmd, "\n"))
		if err != nil {
			return status_fail, err
		}

		status, err = shell.Run()
		if err != nil {
			return status, err
		}
	} else {
		shell := s.NewShell()
		shell.SetDir(s.workspace_folder)
		err := shell.Script("git pull")
		if err != nil {
			return status_fail, err
		}
		status, err = shell.Run()
		if err != nil {
			return status, err
		}
	}

	// 构建
	builders, err := projectBuildRep.GetProjectId(s.project.ID)
	if err != nil {
		return status_fail, err
	}

	for _, v := range builders {
		if v.Command == "" {
			continue
		}
		shell := s.NewShell()
		err := shell.Script(v.Command)
		if err != nil {
			return status_fail, err
		}
		shell.SetDir(s.workspace_folder)
		status, err = shell.Run()
		if err != nil {
			return status, err
		}
	}
	return status_finished, nil
}

func (s *DevOpsWorkSpace) Deploy() (status int, err error) {
	deploies, err := projectDeployRep.GetProjectId(s.project.ID)
	if err != nil {
		return status_fail, err
	}

	for _, deployItem := range deploies {
		serverDto := model.IdsReq{}
		for _, v := range strings.Split(deployItem.ServerIds, ",") {
			id, _ := strconv.Atoi(v)
			serverDto.Ids = append(serverDto.Ids, id)
		}
		servers, err := serverRep.GetIds(serverDto)
		if err != nil {
			return status_fail, nil
		}

		if deployItem.Command == "" {
			continue
		}
		for _, serverItem := range servers {
			var ssh = new(SSH)
			ssh.New(s.logfile)
			ssh.SetEnvs(s.envs)
			addr := fmt.Sprintf("%s:%s", serverItem.IP, strconv.Itoa(serverItem.Port))

			// path, _ := filepath.Abs("c://Users/Administrator/.ssh/id_rsa")
			// key, _ := ioutil.ReadFile(path)
			// ssh.PubKeyConnect(serverItem.Username, addr, key)
			ssh.PasswdConnect(serverItem.Username, serverItem.Password, addr)
			defer ssh.Close()
			ssh.Script(deployItem.Command)

			select {
			case projectId, ok := <-global.DevOpsCancelChan:
				if !ok {
					continue
				}
				if projectId == s.project.ID {
					return status_stop, nil
				}
				global.DevOpsCancelChan <- projectId

			default:
				// close(global.DevOpsCancelChan)
			}
		}
	}
	return status_finished, nil
}

func (s *DevOpsWorkSpace) NewShell() *SHELL {
	shell := new(SHELL)
	shell.New(s.logfile, s.projectId)
	shell.SetEnvs(s.envs)
	return shell
}

func CreateDir(args ...string) string {
	dir := strings.Join(args, "/")
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		os.MkdirAll(dir, os.ModePerm)
	}
	return dir
}
